package xyz.ibenben.zhongdian.system.service.impl;

import com.monitorjbl.xlsx.StreamingReader;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import xyz.ibenben.zhongdian.common.annotation.SystemServiceLog;
import xyz.ibenben.zhongdian.common.constants.Constants;
import xyz.ibenben.zhongdian.common.exception.ExceptionEnum;
import xyz.ibenben.zhongdian.common.exception.MyException;
import xyz.ibenben.zhongdian.common.util.DateUtils;
import xyz.ibenben.zhongdian.common.util.ExcelUtils;
import xyz.ibenben.zhongdian.system.dao.ChinaCityDao;
import xyz.ibenben.zhongdian.system.dao.ChinaProvinceDao;
import xyz.ibenben.zhongdian.system.dao.ChinaRegionDao;
import xyz.ibenben.zhongdian.system.dao.HouseInfoDao;
import xyz.ibenben.zhongdian.system.entity.HouseImage;
import xyz.ibenben.zhongdian.system.entity.HouseInfo;
import xyz.ibenben.zhongdian.system.entity.ajax.AjaxJson;
import xyz.ibenben.zhongdian.system.mapper.HouseInfoMapper;
import xyz.ibenben.zhongdian.system.service.HouseImageService;
import xyz.ibenben.zhongdian.system.service.HouseInfoService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 房屋信息服务实现类
 * 提供了一些基本的服务，如根据主键查找房屋信息及图片、
 * 根据房屋名称查询记录、导出列表等方法。
 * 是此系统的主要服务类
 *
 * @author chenjian
 * @since 2017年9月27日上午10:57:28
 */
@Service
public class HouseInfoServiceImpl extends ServiceImpl<HouseInfo> implements HouseInfoService {
	private final HouseInfoDao houseInfoDao;
	private final HouseInfoMapper houseInfoMapper;
	private final HouseImageService houseImageService;
	private final ChinaProvinceDao chinaProvinceDao;
	private final ChinaCityDao chinaCityDao;
	private final ChinaRegionDao chinaRegionDao;

	@Autowired
	public HouseInfoServiceImpl(HouseInfoDao houseInfoDao, HouseInfoMapper houseInfoMapper, HouseImageService houseImageService, ChinaProvinceDao chinaProvinceDao, ChinaCityDao chinaCityDao, ChinaRegionDao chinaRegionDao) {
		this.houseInfoDao = houseInfoDao;
		this.houseInfoMapper = houseInfoMapper;
		this.houseImageService = houseImageService;
		this.chinaProvinceDao = chinaProvinceDao;
		this.chinaCityDao = chinaCityDao;
		this.chinaRegionDao = chinaRegionDao;
	}

	/**
	 * findOneWithImage房屋信息
	 * @param id 房屋主键
	 * @return 房屋信息
	 */
	@Override
	@Cacheable(cacheNames="houseInfo", key="#id")
	@SystemServiceLog(description = "findOneWithImage房屋信息")
	public HouseInfo findOneWithImage(Long id) {
		HouseInfo info = houseInfoDao.selectByPrimaryKey(id);
		List<HouseImage> list = houseImageService.findByHouseId(id);
		if(list != null && !list.isEmpty()){
			//为房屋信息设置图像列表
			info.setList(list);
		}
		return info;
	}

	/**
	 * findByHouseName房屋信息
	 * @param houseName 房屋名称
	 * @return 房屋信息列表
	 */
	@Override
	@SystemServiceLog(description = "findByHouseName房屋信息")
	public List<HouseInfo> findByHouseName(String houseName) {
		//通过房屋名称获取房屋信息列表
		Example example = new Example(HouseInfo.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("houseName", houseName);
		return houseInfoDao.selectByExample(example);
	}

	/**
	 * export房屋信息
	 * @param houseIds 房屋主键列表
	 * @param request 请求
	 * @param response 响应
	 */
	@Override
	@SystemServiceLog(description = "export房屋信息")
	public void export(List<Long> houseIds, HttpServletRequest request, HttpServletResponse response){
		List<HouseInfo> list;
		if(houseIds != null && !houseIds.isEmpty()){
			//根据主键列表获取数据列表
			Example example = new Example(HouseInfo.class);
			Criteria criteria = example.createCriteria();
			criteria.andIn("id", houseIds);
			list = houseInfoDao.selectByExample(example);
		}else{
			//如果主键列表为空，获取所有数据
			list = houseInfoDao.selectAll();
		}
		response.setHeader("content-Type", "application/vnd.ms-excel");
		// 下载文件的默认名称
		try {
			response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("HouseInfoList","UTF-8") + ".xls");
		} catch (UnsupportedEncodingException e) {
			throw new MyException(ExceptionEnum.CODEEXCEPTION, e);
		}
		//编码
		response.setCharacterEncoding("UTF-8");
		HSSFWorkbook workbook = new HSSFWorkbook();
		//sheet名称
		HSSFSheet sheet = workbook.createSheet("统计表");
		//创建标题
		createTitle(workbook, sheet);
		//设置日期格式
		HSSFCellStyle style = workbook.createCellStyle();
		style.setDataFormat(HSSFDataFormat.getBuiltinFormat("yyyy/mm/dd"));
		//新增数据行，并且设置单元格数据
		int rowNum = 1;
		for (HouseInfo info: list) {
			//导出记录
			HSSFRow row = sheet.createRow(rowNum);
			row.createCell(0).setCellValue(info.getId());
			row.createCell(1).setCellValue(info.getHouseName());
			row.createCell(2).setCellValue(info.getRoomNumber());
			row.createCell(3).setCellValue(info.getDrawingNumber());
			row.createCell(4).setCellValue(info.getKitchenNumber());
			row.createCell(5).setCellValue(info.getRestroomNumber());
			row.createCell(6).setCellValue(info.getOrientation().getText());
			row.createCell(7).setCellValue(info.getHouseArea().doubleValue());
			row.createCell(8).setCellValue(info.getLayer());
			row.createCell(9).setCellValue(info.getTotalLayer());
			row.createCell(10).setCellValue(info.getPolt());
			row.createCell(11).setCellValue(info.getAddress());
			row.createCell(12).setCellValue(chinaProvinceDao.findByCode(info.getProvince()));
			row.createCell(13).setCellValue(chinaCityDao.findByCode(info.getCity()));
			row.createCell(14).setCellValue(chinaRegionDao.findByCode(info.getRegion()));
			row.createCell(15).setCellValue(info.getPurpose());
			row.createCell(16).setCellValue(DateUtils.getCurrentTime(info.getBuyTime(), "yyyy-MM-dd"));
			row.createCell(17).setCellValue(info.getPropertyRight());
			rowNum++;
		}
		try {
			//写到response里
			workbook.write(response.getOutputStream());
		} catch (IOException e) {
			throw new MyException(ExceptionEnum.OUTPUTEXCEPTION, e);
		}
	}
	
	/*** 
	 * 创建表头 
	 * @param workbook 工作簿
	 * @param sheet 工作表
	 */
	private void createTitle(HSSFWorkbook workbook, HSSFSheet sheet){
		HSSFRow row = sheet.createRow(0);
		//设置列宽，setColumnWidth的第二个参数要乘以256，这个参数的单位是1/256个字符宽度
		sheet.setColumnWidth(2, 12*256);
		sheet.setColumnWidth(3, 17*256);
		
		//设置为居中加粗
		HSSFCellStyle style = workbook.createCellStyle();
		HSSFFont font = workbook.createFont();
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		style.setFont(font);
		
		HSSFCell cell;
		//获取标题Map
		Map<String, String> map = Constants.getMap("houseInfo");
		Set<String> set = map.keySet();
		if(set != null && !set.isEmpty()){
			int i = 0;
			for(String value: set){
				//设置标题Title
				cell = row.createCell(i++);
				cell.setCellValue(value);
				cell.setCellStyle(style);
			}
		}
	}

	/**
	 * importData房屋信息
	 * @param bytes 数据数组
	 * @param request 请求
	 */
	@Transactional
	@Override
	@SystemServiceLog(description = "importData房屋信息")
	public void importData(byte[] bytes, HttpServletRequest request){
		//多线程进行导入，每次10行
		int rowNum = 10;
		int totalNum = 0;
		do{
			Workbook wk = StreamingReader.builder()
					.rowCacheSize(rowNum)  //缓存到内存中的行数，默认是10
					.bufferSize(4096)  //读取资源时，缓存到内存的字节大小，默认是1024
					.open(new ByteArrayInputStream(bytes));  //打开资源，必须，可以是InputStream或者是File，注意：只能打开XLSX格式的文件
			Sheet sheet = wk.getSheetAt(0);
			if(totalNum == 0){
				totalNum = sheet.getPhysicalNumberOfRows();
			}
			List<String> list = new ArrayList<>();
			//加入字段名称
			Map<String, String> map = Constants.getMap("houseInfo");
			for (Map.Entry<String, String> entry : map.entrySet()) {
				list.add(entry.getValue());
			}
			//处理数据得到Map
			List<Map<String, Object>> mapList = ExcelUtils.parseExcel(wk, list);
			try {
				//根据Map组装成实体列表
				List<HouseInfo> resultList = ExcelUtils.toObjectList(mapList, HouseInfo.class, "yyyy-MM-dd");
				//保存到数据库
				saveList(resultList, request);
			} catch (Exception e) {
				throw new MyException(ExceptionEnum.SYSTEMERROREXCEPTION, e);
			}
		}while(rowNum <= totalNum);
	}

	/**
	 * 保存列表
	 * @param resultList 需要保存的列表
	 * @param request 请求
	 */
	private void saveList(List<HouseInfo> resultList, HttpServletRequest request) {
		if(resultList != null && !resultList.isEmpty()){
			for(HouseInfo info: resultList){
				//处理省份信息
				String provinceCode = chinaProvinceDao.findByName(info.getProvince());
				info.setProvince(provinceCode);
				//处理城市信息
				String cityCode = chinaCityDao.findByName(info.getCity(), provinceCode);
				info.setCity(cityCode);
				//处理区县信息
				String regionCode = chinaRegionDao.findByName(info.getRegion(), cityCode);
				info.setRegion(regionCode);
				this.save(info, request);
			}
		}
	}

	/**
	 * findByCreateIdAndType房屋信息
	 * @param createId 创建人主键
	 * @param type 类型
	 * @return 房屋信息列表
	 */
	@Override
	@SystemServiceLog(description = "findByCreateIdAndType房屋信息")
	public List<HouseInfo> findByCreateIdAndType(Long createId, int type) {
		Example example = new Example(HouseInfo.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("createId", createId);
		criteria.andEqualTo("type", type);
		return houseInfoDao.selectByExample(example);
	}

	/**
	 * countAll获取所有房屋信息列表
	 * @return 封装好的Json对象
	 */
	@Override
	@SystemServiceLog(description = "countAll获取所有房屋信息列表")
	public AjaxJson getHouseInfoList() {
		AjaxJson aj = new AjaxJson();
		//Map结果集
		Map<String, Object> mapReturn = new HashMap<>();
		List<Map<String, Object>> list = houseInfoMapper.getHouseInfoList();
		if(list != null && !list.isEmpty()){
			//为Echart放置数据，数据是否存在
			mapReturn.put("pieExsit", true);
			List<String> citys = new ArrayList<>();
			List<String> values = new ArrayList<>();
			for(Map<String, Object> map : list){
				citys.add(map.get("city").toString());
				values.add(map.get("count").toString());
			}
			//X轴
			mapReturn.put("pieChatX", citys);
			//Y轴
			mapReturn.put("pieChatY", values);
			aj.setSuccess(true);
		}else{
			//数据不存在
			mapReturn.put("pieExsit", false);
			aj.setSuccess(false);
		}
		aj.setAttributes(mapReturn);
		return aj;
	}
}
